一覧に戻る

Vue+Vue router+AxiosによるAPIエラーハンドリングとページ遷移の実装パターン

#JavaScript#Vue.js#axios#vue-router

この記事について

  • Vueコンポーネント内やVuexのAction内などあちこちでAxiosによるAPIリクエストをしていると、エラーハンドリングを個別に記述しなければならなくなり、DRYではなくなってしまう
  • APIリクエストでエラーが発生した場合に特定のページに遷移させたいのに、Vueインスタンスの外からは$router.push()が呼べない

この記事では、上記のよくある問題をなるべくDRYかつシンプルに解決した方法を述べます。

検証環境

  • Vue2系(Options API、でもcomposition APIでも動くと思う)
  • Vuex(今回の実装には関係ないけれど、Vuexを組み合わせる事も出来る)
  • Vue Router
  • JavaScript

APIリクエストを1箇所で管理する

参考:https://kntmr.hatenablog.com/entry/2018/02/28/200112

各所でAxiosをそのまま用いて非同期通信をすると、それぞれでエラーをcatchしなければなりません。それは辛いので、別にモジュールを用意してAxiosをラップした関数を定義し、その中でエラーハンドリングを行います。基本的に参考サイトのままですが、関数の部分だけ、get, postなどメソッドで分けずに、configで指定するようにしています。


import axios from 'axios'

const debug = process.env.NODE_ENV !== 'production'

const onSuccess = (resp) => {
  if (debug) {
    console.log(' << ' + JSON.stringify(resp.data))
  }
  return Promise.resolve(resp.data)
}
const onError = () => {
  throw new Error('API error.')
}

// リクエストメソッド問わず同じ関数を用いる
const api = (config) => {
    if (debug) {
        console.log(`${config.method} ${config.url} >> ${config.params}`);
    }
    return axios(config)
        .then(onSuccess)
        .catch(onError);
};

export default api;

コンポーネントやVuexでaxios()を使っていた箇所をapi()に置き換えることで、エラーハンドリングの記述が1箇所・1回で済みます、イッツDRY。

エラー時にVue Routerでページ遷移

上記まででエラーハンドリングは1箇所で管理することが出来ました。

さてその際、APIアクセスが失敗した時に、Vue Routerの特定にページに遷移させたい時があります。なので、上記の/src/api/index.jsonError()で、$router.push()したい訳です。

ですがコンポーネントの外(=Vueインスタンスの外)から$router.push()は使うことが出来ません。なのでちょっと工夫します。

Vueインスタンスのexport

Vueプロジェクトのエントリーポイントである/src/main.jsは、Vue CLIでプロジェクトを生成した際は下記のようにVueインスタンスを生成・HTMLを描画しています。


// 略

new Vue({
  render: h => h(App),
}).$mount('#app')

ここで、Vueインスタンスをエクスポートします。


// 略

const vm = new Vue({
  render: h => h(App),
}).$mount('#app')

export default vm;

ここでexportしているvmは、Vueインスタンスのシングルトンです。どこでimportしても常に同一のインスタンスを参照します。

参考:https://qiita.com/NeGI1009/items/f8b17d856a4b15b1ecbc

なので/src/main.jsをimportすればどこからでもVueインスタンスにアクセス出来る訳です。

とはいえ、様々な場所で無秩序にVueインスタンスを操作するのは避けるべきと考えます。

apiモジュールでVueインスタンスにアクセス


import axios from 'axios'

// Vueインスタンス
import vm from '../main';

//略

const onError = () => {
  //エラー時にルートへ遷移
  vm.$router.push('/')
  throw new Error('API error.')
}

//略

この時、Vuex APIにもRouterと同様、vm.$storeでアクセス出来ます。つまりVuexに保存した変数を取得出来るし(getter)、setterやactionを発火させる事も出来ます。

以上でAPIリクエスト時のエラーハンドリングの集中管理およびエラー時のページ遷移が実現しました。あちこちに散逸しがちなエラーハンドリングに対する悪くない実装パターンではないでしょうか。